#ifndef THREAD_HPP_
#define THREAD_HPP_
#include <pthread.h>
#include "system/thread/Mutex.hpp"
#include "exception/Exception.hpp"

namespace SystemThread
{
	/**
	 * Exception that is thrown when the class didn't manage to create a thread.
	 */
	class ThreadCreationException : Exception::BaseException
	{
	public:
		ThreadCreationException():
			BaseException("Thread creation failed."){}
		virtual ~ThreadCreationException(){}
	};

	// for details see below
	void * runWrapped(void *);
	/**
	 * This class is here to allow for easier creation of threads in the
	 * application. It wraps pthread calls so that we can stay stick to the
	 * object oriented approach. It uses some trick by making runWrapped method
	 * a friend, from which we call the exact implementation of the thread that is
	 * the runThreadImpl method. This method is purely abstract so derived classes
	 * has to implement it - this method will be executed as a thread.
	 */
	class Thread
	{
		public:
			/**
			 * Creates new Thread and sets it status to alive.
			 */
			Thread():_alive(true){}
			/**
			 * Nothing special. Just destructor.
			 */
			virtual ~Thread();
			/**
			 * This method should be run to start execution of the the thread. The method
			 * calls the runThreadImpl, that implementation is delivered by derived classes.
			 * It throws exception ThreadCreationException, when it can't create a thread.
			 */
			void run();
			/**
			 * This method wraps pthread_join. To see what join does, check pthread docs.
			 */
			void join();

			/**
			 * This method wraps pthread_exit. Note that this method is static so we the exit
			 * might be called from any place of the Thread. Not only from derived classes.
			 */
			static void exit();

			/**
			 * This methods changes the Thread status from alive = True to alive = False. Note,
			 * that it doesn't kill the thread, but changes its status. The thread might be stopped
			 * then depending on it's status, but the decision when to do it, is left to the client.
			 */
			void kill();

			/**
			 * The tricky method, that is necessary to execute pthread_create. It calls the user implementation
			 * of the thread. The return value doesn't matter from our point of view and is needed only by
			 * pthread library.
			 */
			friend void * runWrapped(void * iThread)
			{
				Thread * aThread = (Thread*)(iThread);
				aThread->runThreadImpl();
				return NULL;
			}
			/**
			 * Checks the status of the thread.
			 *
			 * \return true if thread is alive, or false when someone called kill on the thread.
			 */
			bool isAlive();
		protected:
			/**
			 * This method has to be implemented in derived classes. It contains the code that should be executed
			 * as a seperate Thread.
			 */
			virtual void runThreadImpl() = 0;

			// keeps thread id
			int _threadId;
			// keeps the thread
			pthread_t _thread;
			// mutex used to block operations on the variable _alive
			Mutex _mutex;
			// keeps thread status
			bool _alive;
	};
};

#endif /* THREAD_HPP_ */
